package com.sqlparser.storage.impl;

import com.sqlparser.storage.Storage;
import com.sqlparser.storage.Table;
import com.sqlparser.common.exception.SQLParserException;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 基于文件的存储引擎实现
 */
public class FileStorage implements Storage {
    private static final String DATA_DIR = "data";
    private final Map<String, Table> tableMetadata = new HashMap<>();
    
    @Override
    public List<Map<String, Object>> query(String tableName, List<String> columns, String condition) {
        Table table = loadTable(tableName);
        if (table == null) {
            throw new SQLParserException("Table not found: " + tableName);
        }
        
        List<Map<String, Object>> result = new ArrayList<>();
        List<Map<String, Object>> rows = readTableData(table);
        
        for (Map<String, Object> row : rows) {
            if (evaluateCondition(row, condition)) {
                Map<String, Object> projectedRow = new HashMap<>();
                for (String column : columns) {
                    projectedRow.put(column.toLowerCase(), row.get(column.toLowerCase()));
                }
                result.add(projectedRow);
            }
        }
        
        return result;
    }
    
    @Override
    public void initialize() {
        // 创建数据目录
        new File(DATA_DIR).mkdirs();
        
        // 创建users表
        List<String> columns = Arrays.asList("id", "name", "age", "salary", "createdate");
        Table usersTable = new Table("users", columns);
        tableMetadata.put("users", usersTable);
        
        // 写入示例数据
        List<Map<String, Object>> data = createSampleData();
        writeTableData(usersTable, data);
    }
    
    private List<Map<String, Object>> createSampleData() {
        List<Map<String, Object>> data = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
        try {
            data.add(new HashMap<String, Object>() {{
                put("id", 1);
                put("name", "John");
                put("age", 25);
                put("salary", 5000.0);
                put("createdate", sdf.parse("2024-01-01"));
            }});
            
            data.add(new HashMap<String, Object>() {{
                put("id", 2);
                put("name", "Alice");
                put("age", 30);
                put("salary", 6000.0);
                put("createdate", sdf.parse("2024-01-02"));
            }});
            
            data.add(new HashMap<String, Object>() {{
                put("id", 3);
                put("name", "Bob");
                put("age", 18);
                put("salary", 3000.0);
                put("createdate", sdf.parse("2024-01-03"));
            }});
        } catch (Exception e) {
            throw new RuntimeException("Failed to create sample data", e);
        }
        
        return data;
    }
    
    private void writeTableData(Table table, List<Map<String, Object>> data) {
        File file = new File(DATA_DIR, table.getName() + ".csv");
        try (PrintWriter writer = new PrintWriter(new FileWriter(file))) {
            // 写入列头
            writer.println(String.join(",", table.getColumns()));
            
            // 写入数据行
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            for (Map<String, Object> row : data) {
                List<String> values = new ArrayList<>();
                for (String column : table.getColumns()) {
                    Object value = row.get(column);
                    String strValue = value instanceof Date ? 
                        sdf.format((Date)value) : String.valueOf(value);
                    values.add(strValue);
                }
                writer.println(String.join(",", values));
            }
        } catch (IOException e) {
            throw new SQLParserException("Failed to write table data: " + table.getName(), e);
        }
    }
    
    private List<Map<String, Object>> readTableData(Table table) {
        List<Map<String, Object>> rows = new ArrayList<>();
        File file = new File(DATA_DIR, table.getName() + ".csv");
        
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            // 跳过列头
            reader.readLine();
            
            String line;
            while ((line = reader.readLine()) != null) {
                String[] values = line.split(",");
                Map<String, Object> row = new HashMap<>();
                
                for (int i = 0; i < table.getColumns().size(); i++) {
                    String column = table.getColumns().get(i);
                    String value = values[i];
                    row.put(column, parseValue(value, column));
                }
                
                rows.add(row);
            }
        } catch (IOException e) {
            throw new SQLParserException("Failed to read table data: " + table.getName(), e);
        }
        
        return rows;
    }
    
    private Table loadTable(String tableName) {
        return tableMetadata.get(tableName.toLowerCase());
    }
    
    private Object parseValue(String value, String column) {
        try {
            switch (column.toLowerCase()) {
                case "id":
                case "age":
                    return Integer.parseInt(value);
                case "salary":
                    return Double.parseDouble(value);
                case "createdate":
                    return new SimpleDateFormat("yyyy-MM-dd").parse(value);
                default:
                    return value;
            }
        } catch (Exception e) {
            throw new SQLParserException("Failed to parse value: " + value + " for column: " + column, e);
        }
    }
    
    private boolean evaluateCondition(Map<String, Object> row, String condition) {
        if (condition == null || condition.trim().isEmpty()) {
            return true;
        }
        
        String[] parts = condition.split(" ");
        if (parts.length != 3) {
            throw new SQLParserException("Invalid condition format: " + condition);
        }
        
        String column = parts[0].toLowerCase();
        String operator = parts[1];
        String valueStr = parts[2];
        
        Object rowValue = row.get(column);
        Object conditionValue = parseValue(valueStr, column);
        
        return compare(rowValue, conditionValue, operator);
    }
    
    @SuppressWarnings("unchecked")
    private boolean compare(Object value1, Object value2, String operator) {
        if (value1 == null || value2 == null) {
            return false;
        }
        
        if (value1 instanceof Comparable) {
            int comparison = ((Comparable) value1).compareTo(value2);
            
            switch (operator) {
                case "=":  return comparison == 0;
                case ">":  return comparison > 0;
                case "<":  return comparison < 0;
                case ">=": return comparison >= 0;
                case "<=": return comparison <= 0;
                case "<>": return comparison != 0;
                default:   throw new SQLParserException("Unsupported operator: " + operator);
            }
        }
        
        throw new SQLParserException("Values cannot be compared: " + value1 + " " + operator + " " + value2);
    }
    
    @Override
    public int delete(String tableName, String condition) {
        Table table = loadTable(tableName);
        if (table == null) {
            throw new SQLParserException("Table not found: " + tableName);
        }
        
        List<Map<String, Object>> allRows = readTableData(table);
        List<Map<String, Object>> remainingRows = new ArrayList<>();
        int deletedCount = 0;
        
        // 找出需要保留的行
        for (Map<String, Object> row : allRows) {
            if (!evaluateCondition(row, condition)) {
                remainingRows.add(row);
            } else {
                deletedCount++;
            }
        }
        
        // 重写文件
        writeTableData(table, remainingRows);
        
        return deletedCount;
    }
} 